/*
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

/*
 *
 *
 *
 *
 *
 * Written by Doug Lea with assistance from members of JCP JSR-166
 * Expert Group and released to the public domain, as explained at
 * http://creativecommons.org/publicdomain/zero/1.0/
 */

package java.util.concurrent;

import java.util.AbstractSet;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.NavigableMap;
import java.util.NavigableSet;
import java.util.Set;
import java.util.SortedSet;
import java.util.Spliterator;

/**
 * A scalable concurrent {@link NavigableSet} implementation based on
 * a {@link ConcurrentSkipListMap}.  The elements of the set are kept
 * sorted according to their {@linkplain Comparable natural ordering},
 * or by a {@link Comparator} provided at set creation time, depending
 * on which constructor is used.
 *
 * <p>This implementation provides expected average <i>log(n)</i> time
 * cost for the {@code contains}, {@code add}, and {@code remove}
 * operations and their variants.  Insertion, removal, and access
 * operations safely execute concurrently by multiple threads.
 *
 * <p>Iterators and spliterators are
 * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
 *
 * <p>Ascending ordered views and their iterators are faster than
 * descending ones.
 *
 * <p>Beware that, unlike in most collections, the {@code size}
 * method is <em>not</em> a constant-time operation. Because of the
 * asynchronous nature of these sets, determining the current number
 * of elements requires a traversal of the elements, and so may report
 * inaccurate results if this collection is modified during traversal.
 * Additionally, the bulk operations {@code addAll},
 * {@code removeAll}, {@code retainAll}, {@code containsAll},
 * {@code equals}, and {@code toArray} are <em>not</em> guaranteed
 * to be performed atomically. For example, an iterator operating
 * concurrently with an {@code addAll} operation might view only some
 * of the added elements.
 *
 * <p>This class and its iterators implement all of the
 * <em>optional</em> methods of the {@link Set} and {@link Iterator}
 * interfaces. Like most other concurrent collection implementations,
 * this class does not permit the use of {@code null} elements,
 * because {@code null} arguments and return values cannot be reliably
 * distinguished from the absence of elements.
 *
 * <p>This class is a member of the
 * <a href="{@docRoot}/../technotes/guides/collections/index.html">
 * Java Collections Framework</a>.
 *
 * @param <E> the type of elements maintained by this set
 * @author Doug Lea
 * @since 1.6
 */
public class ConcurrentSkipListSet<E>
    extends AbstractSet<E>
    implements NavigableSet<E>, Cloneable, java.io.Serializable {

  private static final long serialVersionUID = -2479143111061671589L;

  /**
   * The underlying map. Uses Boolean.TRUE as value for each
   * element.  This field is declared final for the sake of thread
   * safety, which entails some ugliness in clone().
   */
  private final ConcurrentNavigableMap<E, Object> m;

  /**
   * Constructs a new, empty set that orders its elements according to
   * their {@linkplain Comparable natural ordering}.
   */
  public ConcurrentSkipListSet() {
    m = new ConcurrentSkipListMap<E, Object>();
  }

  /**
   * Constructs a new, empty set that orders its elements according to
   * the specified comparator.
   *
   * @param comparator the comparator that will be used to order this set. If {@code null}, the
   * {@linkplain Comparable natural ordering} of the elements will be used.
   */
  public ConcurrentSkipListSet(Comparator<? super E> comparator) {
    m = new ConcurrentSkipListMap<E, Object>(comparator);
  }

  /**
   * Constructs a new set containing the elements in the specified
   * collection, that orders its elements according to their
   * {@linkplain Comparable natural ordering}.
   *
   * @param c The elements that will comprise the new set
   * @throws ClassCastException if the elements in {@code c} are not {@link Comparable}, or are not
   * mutually comparable
   * @throws NullPointerException if the specified collection or any of its elements are null
   */
  public ConcurrentSkipListSet(Collection<? extends E> c) {
    m = new ConcurrentSkipListMap<E, Object>();
    addAll(c);
  }

  /**
   * Constructs a new set containing the same elements and using the
   * same ordering as the specified sorted set.
   *
   * @param s sorted set whose elements will comprise the new set
   * @throws NullPointerException if the specified sorted set or any of its elements are null
   */
  public ConcurrentSkipListSet(SortedSet<E> s) {
    m = new ConcurrentSkipListMap<E, Object>(s.comparator());
    addAll(s);
  }

  /**
   * For use by submaps
   */
  ConcurrentSkipListSet(ConcurrentNavigableMap<E, Object> m) {
    this.m = m;
  }

  /**
   * Returns a shallow copy of this {@code ConcurrentSkipListSet}
   * instance. (The elements themselves are not cloned.)
   *
   * @return a shallow copy of this set
   */
  public ConcurrentSkipListSet<E> clone() {
    try {
      @SuppressWarnings("unchecked")
      ConcurrentSkipListSet<E> clone =
          (ConcurrentSkipListSet<E>) super.clone();
      clone.setMap(new ConcurrentSkipListMap<E, Object>(m));
      return clone;
    } catch (CloneNotSupportedException e) {
      throw new InternalError();
    }
  }

    /* ---------------- Set operations -------------- */

  /**
   * Returns the number of elements in this set.  If this set
   * contains more than {@code Integer.MAX_VALUE} elements, it
   * returns {@code Integer.MAX_VALUE}.
   *
   * <p>Beware that, unlike in most collections, this method is
   * <em>NOT</em> a constant-time operation. Because of the
   * asynchronous nature of these sets, determining the current
   * number of elements requires traversing them all to count them.
   * Additionally, it is possible for the size to change during
   * execution of this method, in which case the returned result
   * will be inaccurate. Thus, this method is typically not very
   * useful in concurrent applications.
   *
   * @return the number of elements in this set
   */
  public int size() {
    return m.size();
  }

  /**
   * Returns {@code true} if this set contains no elements.
   *
   * @return {@code true} if this set contains no elements
   */
  public boolean isEmpty() {
    return m.isEmpty();
  }

  /**
   * Returns {@code true} if this set contains the specified element.
   * More formally, returns {@code true} if and only if this set
   * contains an element {@code e} such that {@code o.equals(e)}.
   *
   * @param o object to be checked for containment in this set
   * @return {@code true} if this set contains the specified element
   * @throws ClassCastException if the specified element cannot be compared with the elements
   * currently in this set
   * @throws NullPointerException if the specified element is null
   */
  public boolean contains(Object o) {
    return m.containsKey(o);
  }

  /**
   * Adds the specified element to this set if it is not already present.
   * More formally, adds the specified element {@code e} to this set if
   * the set contains no element {@code e2} such that {@code e.equals(e2)}.
   * If this set already contains the element, the call leaves the set
   * unchanged and returns {@code false}.
   *
   * @param e element to be added to this set
   * @return {@code true} if this set did not already contain the specified element
   * @throws ClassCastException if {@code e} cannot be compared with the elements currently in this
   * set
   * @throws NullPointerException if the specified element is null
   */
  public boolean add(E e) {
    return m.putIfAbsent(e, Boolean.TRUE) == null;
  }

  /**
   * Removes the specified element from this set if it is present.
   * More formally, removes an element {@code e} such that
   * {@code o.equals(e)}, if this set contains such an element.
   * Returns {@code true} if this set contained the element (or
   * equivalently, if this set changed as a result of the call).
   * (This set will not contain the element once the call returns.)
   *
   * @param o object to be removed from this set, if present
   * @return {@code true} if this set contained the specified element
   * @throws ClassCastException if {@code o} cannot be compared with the elements currently in this
   * set
   * @throws NullPointerException if the specified element is null
   */
  public boolean remove(Object o) {
    return m.remove(o, Boolean.TRUE);
  }

  /**
   * Removes all of the elements from this set.
   */
  public void clear() {
    m.clear();
  }

  /**
   * Returns an iterator over the elements in this set in ascending order.
   *
   * @return an iterator over the elements in this set in ascending order
   */
  public Iterator<E> iterator() {
    return m.navigableKeySet().iterator();
  }

  /**
   * Returns an iterator over the elements in this set in descending order.
   *
   * @return an iterator over the elements in this set in descending order
   */
  public Iterator<E> descendingIterator() {
    return m.descendingKeySet().iterator();
  }


    /* ---------------- AbstractSet Overrides -------------- */

  /**
   * Compares the specified object with this set for equality.  Returns
   * {@code true} if the specified object is also a set, the two sets
   * have the same size, and every member of the specified set is
   * contained in this set (or equivalently, every member of this set is
   * contained in the specified set).  This definition ensures that the
   * equals method works properly across different implementations of the
   * set interface.
   *
   * @param o the object to be compared for equality with this set
   * @return {@code true} if the specified object is equal to this set
   */
  public boolean equals(Object o) {
    // Override AbstractSet version to avoid calling size()
    if (o == this) {
      return true;
    }
    if (!(o instanceof Set)) {
      return false;
    }
    Collection<?> c = (Collection<?>) o;
    try {
      return containsAll(c) && c.containsAll(this);
    } catch (ClassCastException unused) {
      return false;
    } catch (NullPointerException unused) {
      return false;
    }
  }

  /**
   * Removes from this set all of its elements that are contained in
   * the specified collection.  If the specified collection is also
   * a set, this operation effectively modifies this set so that its
   * value is the <i>asymmetric set difference</i> of the two sets.
   *
   * @param c collection containing elements to be removed from this set
   * @return {@code true} if this set changed as a result of the call
   * @throws ClassCastException if the types of one or more elements in this set are incompatible
   * with the specified collection
   * @throws NullPointerException if the specified collection or any of its elements are null
   */
  public boolean removeAll(Collection<?> c) {
    // Override AbstractSet version to avoid unnecessary call to size()
    boolean modified = false;
    for (Object e : c) {
      if (remove(e)) {
        modified = true;
      }
    }
    return modified;
  }

    /* ---------------- Relational operations -------------- */

  /**
   * @throws ClassCastException {@inheritDoc}
   * @throws NullPointerException if the specified element is null
   */
  public E lower(E e) {
    return m.lowerKey(e);
  }

  /**
   * @throws ClassCastException {@inheritDoc}
   * @throws NullPointerException if the specified element is null
   */
  public E floor(E e) {
    return m.floorKey(e);
  }

  /**
   * @throws ClassCastException {@inheritDoc}
   * @throws NullPointerException if the specified element is null
   */
  public E ceiling(E e) {
    return m.ceilingKey(e);
  }

  /**
   * @throws ClassCastException {@inheritDoc}
   * @throws NullPointerException if the specified element is null
   */
  public E higher(E e) {
    return m.higherKey(e);
  }

  public E pollFirst() {
    Map.Entry<E, Object> e = m.pollFirstEntry();
    return (e == null) ? null : e.getKey();
  }

  public E pollLast() {
    Map.Entry<E, Object> e = m.pollLastEntry();
    return (e == null) ? null : e.getKey();
  }


    /* ---------------- SortedSet operations -------------- */


  public Comparator<? super E> comparator() {
    return m.comparator();
  }

  /**
   * @throws java.util.NoSuchElementException {@inheritDoc}
   */
  public E first() {
    return m.firstKey();
  }

  /**
   * @throws java.util.NoSuchElementException {@inheritDoc}
   */
  public E last() {
    return m.lastKey();
  }

  /**
   * @throws ClassCastException {@inheritDoc}
   * @throws NullPointerException if {@code fromElement} or {@code toElement} is null
   * @throws IllegalArgumentException {@inheritDoc}
   */
  public NavigableSet<E> subSet(E fromElement,
      boolean fromInclusive,
      E toElement,
      boolean toInclusive) {
    return new ConcurrentSkipListSet<E>
        (m.subMap(fromElement, fromInclusive,
            toElement, toInclusive));
  }

  /**
   * @throws ClassCastException {@inheritDoc}
   * @throws NullPointerException if {@code toElement} is null
   * @throws IllegalArgumentException {@inheritDoc}
   */
  public NavigableSet<E> headSet(E toElement, boolean inclusive) {
    return new ConcurrentSkipListSet<E>(m.headMap(toElement, inclusive));
  }

  /**
   * @throws ClassCastException {@inheritDoc}
   * @throws NullPointerException if {@code fromElement} is null
   * @throws IllegalArgumentException {@inheritDoc}
   */
  public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
    return new ConcurrentSkipListSet<E>(m.tailMap(fromElement, inclusive));
  }

  /**
   * @throws ClassCastException {@inheritDoc}
   * @throws NullPointerException if {@code fromElement} or {@code toElement} is null
   * @throws IllegalArgumentException {@inheritDoc}
   */
  public NavigableSet<E> subSet(E fromElement, E toElement) {
    return subSet(fromElement, true, toElement, false);
  }

  /**
   * @throws ClassCastException {@inheritDoc}
   * @throws NullPointerException if {@code toElement} is null
   * @throws IllegalArgumentException {@inheritDoc}
   */
  public NavigableSet<E> headSet(E toElement) {
    return headSet(toElement, false);
  }

  /**
   * @throws ClassCastException {@inheritDoc}
   * @throws NullPointerException if {@code fromElement} is null
   * @throws IllegalArgumentException {@inheritDoc}
   */
  public NavigableSet<E> tailSet(E fromElement) {
    return tailSet(fromElement, true);
  }

  /**
   * Returns a reverse order view of the elements contained in this set.
   * The descending set is backed by this set, so changes to the set are
   * reflected in the descending set, and vice-versa.
   *
   * <p>The returned set has an ordering equivalent to
   * {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}{@code (comparator())}.
   * The expression {@code s.descendingSet().descendingSet()} returns a
   * view of {@code s} essentially equivalent to {@code s}.
   *
   * @return a reverse order view of this set
   */
  public NavigableSet<E> descendingSet() {
    return new ConcurrentSkipListSet<E>(m.descendingMap());
  }

  /**
   * Returns a {@link Spliterator} over the elements in this set.
   *
   * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
   * {@link Spliterator#NONNULL}, {@link Spliterator#DISTINCT},
   * {@link Spliterator#SORTED} and {@link Spliterator#ORDERED}, with an
   * encounter order that is ascending order.  Overriding implementations
   * should document the reporting of additional characteristic values.
   *
   * <p>The spliterator's comparator (see
   * {@link java.util.Spliterator#getComparator()}) is {@code null} if
   * the set's comparator (see {@link #comparator()}) is {@code null}.
   * Otherwise, the spliterator's comparator is the same as or imposes the
   * same total ordering as the set's comparator.
   *
   * @return a {@code Spliterator} over the elements in this set
   * @since 1.8
   */
  @SuppressWarnings("unchecked")
  public Spliterator<E> spliterator() {
    if (m instanceof ConcurrentSkipListMap) {
      return ((ConcurrentSkipListMap<E, ?>) m).keySpliterator();
    } else {
      return (Spliterator<E>) ((ConcurrentSkipListMap.SubMap<E, ?>) m).keyIterator();
    }
  }

  // Support for resetting map in clone
  private void setMap(ConcurrentNavigableMap<E, Object> map) {
    UNSAFE.putObjectVolatile(this, mapOffset, map);
  }

  private static final sun.misc.Unsafe UNSAFE;
  private static final long mapOffset;

  static {
    try {
      UNSAFE = sun.misc.Unsafe.getUnsafe();
      Class<?> k = ConcurrentSkipListSet.class;
      mapOffset = UNSAFE.objectFieldOffset
          (k.getDeclaredField("m"));
    } catch (Exception e) {
      throw new Error(e);
    }
  }
}
